package com.oig.sys.auth.service.impl;

import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.util.JsonUtil;
import com.oig.sys.auth.constants.AuthEnums;
import com.oig.sys.auth.dao.ITbDepartUserDao;
import com.oig.sys.auth.dao.ITbResourceDao;
import com.oig.sys.auth.dao.ITbResourceDataCfgDao;
import com.oig.sys.auth.dao.ITbTenantInfoDao;
import com.oig.sys.auth.dao.ITbUserJobDao;
import com.oig.sys.auth.dao.ITbUserRoleDao;
import com.oig.sys.auth.dto.ResourceDataCfgDto;
import com.oig.sys.auth.dto.UserMiniDto;
import com.oig.sys.auth.entity.TbDepartUser;
import com.oig.sys.auth.entity.TbResource;
import com.oig.sys.auth.entity.TbResourceDataCfg;
import com.oig.sys.auth.entity.TbTenantInfo;
import com.oig.sys.auth.entity.TbUserJob;
import com.oig.sys.auth.entity.TbUserRole;
import com.oig.sys.auth.service.ITbResourceDataCfgService;
import com.oig.sys.auth.vo.ResourceDataCfgVo;
import com.oig.sys.auth.vo.UserDataCfgVo;
import com.oig.sys.security.support.SecurityUser;
import com.oig.sys.security.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wuxl
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TbResourceDataCfgServiceImpl implements ITbResourceDataCfgService {

	private final ITbResourceDataCfgDao tbResourceDataCfgDao;
	private final ITbResourceDao resourceDao;
	private final ITbUserRoleDao userRoleDao;
	private final ITbUserJobDao userJobDao;
	private final ITbDepartUserDao departUserDao;
	private final ITbTenantInfoDao tenantInfoDao;




	@Override
	public List<ResourceDataCfgVo> getResourceDataCfg(Integer resourceId) {
		if (SecurityUtil.getDefineUserMain().getTenantId()==0){
			return this.tbResourceDataCfgDao.findAllResourceDataCfg(resourceId);
		}
		return this.tbResourceDataCfgDao.findUseResourceDataCfg(resourceId, SecurityUtil.getDefineUserMain().getTenantId());
	}

	private void checkData(ResourceDataCfgDto resourceDataCfgDto){
		TbResource resource = this.resourceDao.getTbResourceById(resourceDataCfgDto.getResourceId());
		if (resource==null||!CommonEnum.CommonStatusEnum.OK.getCode().equals(resource.getStatus())){
			throw new BadRequestException("菜单不存在或未生效") ;
		}
		if (resource.getLevel()!=2){
			log.warn("warn resource date cfg: resource:{}, level=={}",resource.getResourceName(), resource.getLevel());
			throw new BadRequestException("二级菜单才能配置数据权限");
		}
		if (AuthEnums.DataCfgEqType.USERID.getCode().equals(resourceDataCfgDto.getDataEqType())){
			if (StringUtils.isBlank(resourceDataCfgDto.getDataEqFiled())){
				throw new BadRequestException("数据过滤匹配字段必须指定");
			}
		} else if (AuthEnums.DataCfgEqType.FIXED.getCode().equals(resourceDataCfgDto.getDataEqType())){
			if (StringUtils.isBlank(resourceDataCfgDto.getDataEqSql())){
				throw new BadRequestException("数据过滤对应固定值必填");
			}
		} else if (AuthEnums.DataCfgEqType.OTHER.getCode().equals(resourceDataCfgDto.getDataEqType())){
			if (StringUtils.isBlank(resourceDataCfgDto.getDataEqSql())){
				throw new BadRequestException("数据过滤sql模板必填");
			}
		} else {
			if (StringUtils.isBlank(resourceDataCfgDto.getExcludeField())){
				throw new BadRequestException("错误的配置") ;
			}
		}
		if (resourceDataCfgDto.getTenantId()!=null){
			SecurityUtil.getDefineUserMain().checkTenantPermission(resourceDataCfgDto.getTenantId());
			if (StringUtils.isBlank(resourceDataCfgDto.getTenantName())){
				TbTenantInfo tenantInfo = this.tenantInfoDao.getTbTenantInfoById(resourceDataCfgDto.getTenantId());
				resourceDataCfgDto.setTenantCode(tenantInfo.getCode());
				resourceDataCfgDto.setTenantName(tenantInfo.getName());
			}
		}
	}

	@Transactional
	@Override
	public ResourceDataCfgVo addResourceDataCfg(ResourceDataCfgDto resourceDataCfgDto) {
		this.checkData(resourceDataCfgDto);
		TbResourceDataCfg resourceDataCfg = new TbResourceDataCfg();
		BeanUtils.copyProperties(resourceDataCfgDto, resourceDataCfg, "id");
		resourceDataCfg.setCreateTime(new Date());
		resourceDataCfg.setCreateUserId(SecurityUtil.getDefineUserMain().getId());
		resourceDataCfg.setCreateUserName(SecurityUtil.getDefineUserMain().getRealName());
		resourceDataCfg.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		this.tbResourceDataCfgDao.save(resourceDataCfg);
		ResourceDataCfgVo resourceDataCfgVo = new ResourceDataCfgVo();
		BeanUtils.copyProperties(resourceDataCfg, resourceDataCfgVo);
		return resourceDataCfgVo;
	}

	private void checkRole(TbResourceDataCfg resourceDataCfg){
		if (resourceDataCfg==null){
			throw new BadRequestException("配置不存在") ;
		}
		SecurityUtil.getDefineUserMain().checkTenantPermission(resourceDataCfg.getTenantId());
	}

	@Transactional
	@Override
	public ResourceDataCfgVo updateResourceDataCfg(ResourceDataCfgDto resourceDataCfgDto) {
		this.checkData(resourceDataCfgDto);
		TbResourceDataCfg resourceDataCfg = this.tbResourceDataCfgDao.getTbResourceDataCfgById(resourceDataCfgDto.getId()) ;
		this.checkRole(resourceDataCfg);
		BeanUtils.copyProperties(resourceDataCfgDto, resourceDataCfg,"id", "resourceId");
		SecurityUser securityUser = SecurityUtil.getDefineUserMain();
		resourceDataCfg.setLastUpdateTime(new Date());
		resourceDataCfg.setLastUpdateId(securityUser.getId());
		resourceDataCfg.setLastUpdateName(securityUser.getRealName());
		this.tbResourceDataCfgDao.save(resourceDataCfg);
		ResourceDataCfgVo resourceDataCfgVo = new ResourceDataCfgVo();
		BeanUtils.copyProperties(resourceDataCfg, resourceDataCfgVo);
		return resourceDataCfgVo;
	}

	@Transactional
	@Override
	public void cancelResourceDataCfg(Integer id) {
		TbResourceDataCfg resourceDataCfg = this.tbResourceDataCfgDao.getTbResourceDataCfgById(id) ;
		this.checkRole(resourceDataCfg);
		resourceDataCfg.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
		this.tbResourceDataCfgDao.save(resourceDataCfg);
	}

	@Transactional
	@Override
	public void revertResourceDataCfg(Integer id) {
		TbResourceDataCfg resourceDataCfg = this.tbResourceDataCfgDao.getTbResourceDataCfgById(id) ;
		this.checkRole(resourceDataCfg);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(resourceDataCfg.getStatus())){
			throw new BadRequestException("非注销状态") ;
		}
		resourceDataCfg.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());	//add的时候是ok，恢复直接是ok
		this.tbResourceDataCfgDao.save(resourceDataCfg);
	}

	@Transactional
	@Override
	public void delResourceDataCfg(Integer id) {
		TbResourceDataCfg resourceDataCfg = this.tbResourceDataCfgDao.getTbResourceDataCfgById(id) ;
		this.checkRole(resourceDataCfg);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(resourceDataCfg.getStatus())){
			throw new BadRequestException("注销状态才能清除数据") ;
		}
		this.tbResourceDataCfgDao.delete(resourceDataCfg);
	}

	@Override
	public UserDataCfgVo getUserDataCfg(Integer resourceId) {
		SecurityUser securityUser = SecurityUtil.getDefineUserMain() ;
		UserDataCfgVo userDataCfgVo = new UserDataCfgVo() ;
		List<ResourceDataCfgVo> useResDataCfgList=tbResourceDataCfgDao.findUseResourceDataCfg(resourceId,securityUser.getTenantId(),CommonEnum.CommonStatusEnum.OK.getCode()) ;
		if (useResDataCfgList==null || useResDataCfgList.isEmpty()){
			log.debug("resource have not data config");
			return userDataCfgVo;
		}
		Map<String,List<String>> eqTypeFields = null;
		Map<String,String> eqFieldValueMap = null;
		List<String> excludeFieldList = null;
		for (ResourceDataCfgVo resourceDataCfgVo : useResDataCfgList){
			//用户在白名单跳过
			boolean outUser = false;
			if (StringUtils.isNotBlank(resourceDataCfgVo.getWhitelist())){
				List<UserMiniDto> whiteList = JsonUtil.toList(resourceDataCfgVo.getWhitelist(), UserMiniDto.class) ;
				for (UserMiniDto userMiniDto : whiteList){
					if (securityUser.getId().equals(userMiniDto.getId())){
						log.debug("user:{},in white list", securityUser.getNickName());
						outUser = true;
						break;
					}
				}
			}
			if (outUser) continue;
			//用户不在限制范围跳过
			if (AuthEnums.DataCfgUserLimitType.ROLE.getCode().equals(resourceDataCfgVo.getUserRelationType())){
				TbUserRole userRole = userRoleDao.getByUserIdAndRoleId(securityUser.getId(),resourceDataCfgVo.getUserRelationId());
				if (userRole==null) continue;
			} else if (AuthEnums.DataCfgUserLimitType.JOB.getCode().equals(resourceDataCfgVo.getUserRelationType())){
				TbUserJob userJob = userJobDao.getByUserIdAndJobId(securityUser.getId(),resourceDataCfgVo.getUserRelationId()) ;
				if (userJob==null) continue;
			} else if (AuthEnums.DataCfgUserLimitType.DEPART.getCode().equals(resourceDataCfgVo.getUserRelationType())){
				TbDepartUser departUser = departUserDao.getByDepartIdAndUserId(resourceDataCfgVo.getUserRelationId(), securityUser.getId()) ;
				if (departUser==null) continue;
			}
			// 添加到，条件
			log.debug("user:{}---RDF:{}",securityUser.getId(),resourceDataCfgVo);
			if (AuthEnums.DataCfgEqType.USERID.getCode().equals(resourceDataCfgVo.getDataEqType())){
				if(eqTypeFields==null) eqTypeFields =new HashMap<>();
				List<String> userEqFields = eqTypeFields.get(AuthEnums.DataCfgEqType.USERID.getCode());
				if (userEqFields==null){
					userEqFields = new ArrayList<>();
				}
				userEqFields.add(resourceDataCfgVo.getDataEqFiled()) ;
				eqTypeFields.put(AuthEnums.DataCfgEqType.USERID.getCode(),userEqFields);
			} else if (AuthEnums.DataCfgEqType.FIXED.getCode().equals(resourceDataCfgVo.getDataEqType())){
				if (eqFieldValueMap==null) eqFieldValueMap = new HashMap<>();
				eqFieldValueMap.put(resourceDataCfgVo.getDataEqFiled(), resourceDataCfgVo.getDataEqSql());
			}
			if (StringUtils.isNotBlank(resourceDataCfgVo.getExcludeField())){
				if (excludeFieldList==null) excludeFieldList = new ArrayList<>();
				excludeFieldList.addAll(JsonUtil.toList(resourceDataCfgVo.getExcludeField(),String.class));
			}
		}
		userDataCfgVo.setEqTypeFields(eqTypeFields);
		userDataCfgVo.setEqFieldValue(eqFieldValueMap);
		userDataCfgVo.setExcludeFields(excludeFieldList);
		return userDataCfgVo;
	}




}
